/*
 * Copyright 2012 Andrea Parodi
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package eban.storebyrules;

import lombok.extern.log4j.Log4j;

/**
 * Author: parroit
 * Created: 09/05/12 19.26
 */
@Log4j
public abstract class AbstractTransaction implements Transaction {
    private AbstractStorage storage;

    public AbstractTransaction(AbstractStorage sqliteDbManager, boolean writeOnlyTransaction) {
        this.storage = sqliteDbManager;
        this.writeOnlyTransaction = writeOnlyTransaction;
    }

    public AbstractTransaction(AbstractStorage sqliteDbManager) {
        this.storage = sqliteDbManager;
        this.writeOnlyTransaction = false;
    }

    private final boolean writeOnlyTransaction;
    private StringBuilder commandsBuffer = new StringBuilder();

    @Override
    public void execute(String sql) {
        storage.checkSameThreadAsConstructionTime();
        storage.checkIsCurrentTransaction(this);
        storage.checkDbExists();

        if (AbstractTransaction.log.isDebugEnabled())
            AbstractTransaction.log.debug("Executing sql " + sql);
        if (writeOnlyTransaction) {
           commandsBuffer.append(sql+";\r\n");
           if (commandsBuffer.length()>20000)
           {
               storage.executeInternal(commandsBuffer.toString());
               storage.executeInternal("COMMIT");
               commandsBuffer.setLength(0);
               //commandsBuffer=new StringBuilder();
               //System.out.println("cap:"+commandsBuffer.capacity());
               storage.executeInternal("BEGIN TRANSACTION");
           }


        } else {
            storage.executeInternal(sql);

        }

    }


    @Override public void commit() {
        storage.checkSameThreadAsConstructionTime();
        storage.checkIsCurrentTransaction(this);
        try {
            if (AbstractTransaction.log.isDebugEnabled())
                AbstractTransaction.log.debug("Committing transaction");
            if (writeOnlyTransaction && commandsBuffer.length()>0 ){
                storage.executeInternal(commandsBuffer.toString());

            }
            storage.commitInternal();


            dispose();
            if (AbstractTransaction.log.isDebugEnabled())
                AbstractTransaction.log.debug("Transaction committed");
        } catch (Exception e) {
            throw new PersistenceException("Unable to commit transaction", e);

        }
    }


    @Override public void rollback() {
        storage.checkSameThreadAsConstructionTime();
        storage.checkIsCurrentTransaction(this);
        try {
            if (AbstractTransaction.log.isDebugEnabled())
                AbstractTransaction.log.debug("Rolling back transaction");
            if (!writeOnlyTransaction)
                storage.rollbackInternal();
            dispose();
            if (AbstractTransaction.log.isDebugEnabled())
                AbstractTransaction.log.debug("Rolled back transaction");
        } catch (Exception e) {
            throw new PersistenceException("Unable to rollback transaction", e);

        }
    }

    @Override public void dispose() {
        storage.checkSameThreadAsConstructionTime();
        storage.checkIsCurrentTransaction(this);
        storage.disposeCurrentTransaction();
    }

}
